package org.jeecg.modules.simulator.rooter;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.simulator.jsonot.NumPeopEnStationApiInfo;
import org.jeecg.modules.simulator.jsonot.ODProbabilityApiInfo;
import org.jeecg.modules.simulator.jsonot.PsgStationDistributionInfo;
import org.jeecg.modules.simulator.model.MetroTrain;
import org.jeecg.modules.simulator.model.OffTrainNumRange;
import org.jeecg.modules.simulator.model.SceneDataType;
import org.jeecg.modules.simulator.model.SceneParam;
import org.jeecg.modules.simulator.model.line.Line;
import org.jeecg.modules.simulator.model.line.park.Parker;
import org.jeecg.modules.simulator.model.line.station.station.HistoryOdParamService;
import org.jeecg.modules.simulator.model.line.station.station.HistoryTimePeriodOdParamService;
import org.jeecg.modules.simulator.model.line.station.station.Station;
import org.jeecg.modules.simulator.model.line.station.station.TransferStation;
import org.jeecg.modules.simulator.model.person.Person;
import org.jeecg.modules.simulator.model.person.path.PersonPath;
import org.jeecg.modules.simulator.model.train.timeplan.TrainPlanTable;
import org.jeecg.modules.simulator.util.UnitCache;

import java.time.LocalTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @program: simulator-b20240918
 * @description:
 * @author: renzhg
 * @create: 2024-10-24 13:21
 **/
@Slf4j
public class RooterInitializer {
    private static final Logger logger = LoggerFactory.getLogger(RooterInitializer.class);


    @Setter
    @Getter
    String sceneCode;
    @Setter
    Map<String, LineRooter> lineRooterMap = new HashMap<>();
    @Setter
    @Getter
    Map<String, Station> stationMap = new HashMap<>();
    @Setter
    @Getter
    //换乘站集合
    Map<String, TransferStation> transferStationMap = new HashMap<>();//换乘站集合
    @Setter
    @Getter
    //key:路径序号+首站点名称
    Map<String, PersonPath> personPathMap = new HashMap<>();
    @Setter
    @Getter
    Map<String, Map<String, List<Person>>> personTrainMapByLine = new HashMap<>();
    @Setter
    @Getter
    //按线路分的station
    Map<String, List<Station>> linesStationMap = new HashMap<>();
    @Setter
    @Getter
    //stationName,使用站名做Key
    Map<String, Station> stationNameMap = new HashMap<>();
    @Setter
    @Getter
    Map<String, Line> lineAllMap = new HashMap<>();
    @Setter
    @Getter
    //按线路分配的场段字典
    Map<String, List<Parker>> parkerMap = new HashMap<>();

    @Setter
    @Getter
    Map<String, List<TrainPlanTable>> trainPlanTableMapByLine = new HashMap<>();

    @Setter
    @Getter
    Map<String, List<PsgStationDistributionInfo>> psgStationDistributionInfoMap = new HashMap<>();


    @Setter
    @Getter
    //各站人员OD分配概率(List<ODProbabilityApiInfo> 是路径信息，一个od有多个路径)
    Map<String, List<ODProbabilityApiInfo>> odProbabilityApiInfoMap = new HashMap<>();

    @Setter
    @Getter
        Map<String, Map<String, NumPeopEnStationApiInfo>> numPeopEnStationApiInfoMap = new HashMap<>();

    @Getter
    //未分配的列车
    Map<String, List<MetroTrain>> metroTrainNoAssigeMap = new HashMap<>();


    @Getter
    Map<String, Line> lineMap = new HashMap<>();
    @Getter
    Map<String, String> startTimeMap = new HashMap<>();

/**
 * @description: 始化网络模拟器，通过设置各种配置和映射。
 * 列车时刻表转换成列车动作对象，
 *
 *将人员分配到列车上、以及设置站点和换乘站数据。
 *
 * @author:  renzhg 
 * @date:  2024/11/16 11:01
 **/
//    public void initTrainTableBizData() {
//        NetInitializer netInitializer= netInitializer();//初始化方法所需要的参数设定
//        /**
//         * @description: 初始化网络模拟器，通过设置各种配置和映射。
//         *  *这包括初始化线路路由器、将人员分配到列车上、以及设置站点和换乘站数据。
//         *
//         * @author:  renzhg
//         * @date:  2024/11/16 11:01
//         **/
//        netInitializer.initNetSimulator();
//        //按停车场分配的车辆
//
//    }

    public void initTrainTableBizData() {
        NetInitializer netInitializer= netInitializer();//初始化方法所需要的参数设定
        /**
         * @description: 初始化网络模拟器，通过设置各种配置和映射。
         *  *这包括初始化线路路由器、将人员分配到列车上、以及设置站点和换乘站数据。
         *
         * @author:  renzhg
         * @date:  2024/11/16 11:01
         **/
        SceneParam sceneParam = UnitCache.sceneParamMap.get(sceneCode);
//        netInitializer.initTrainManagers(sceneParam);
        if (sceneParam.getSceneType().equals(SceneDataType.timePeriodHistoryData)) {
            netInitializer.initPeriodTimeManagers();
            netInitializer.timePeriodHistory(sceneParam);
        } else if (sceneParam.getSceneType().equals(SceneDataType.allDayHistoryData)) {
            netInitializer.initTrainAllDayManagers();//列车时刻表装配
            netInitializer.initAllDayStations();//设定站点的参数
        }

//        netInitializer.initNetSimulator();
        //按停车场分配的车辆

    }


    //初始化网络装配工程
    public NetInitializer netInitializer() {
        NetInitializer netInitializer = new NetInitializer();
        netInitializer.setLineRooterMap(lineRooterMap);
        netInitializer.setStationMap(stationMap);
        netInitializer.setTransferStationMap(transferStationMap);
        netInitializer.setPsgStationDistributionInfoMap(psgStationDistributionInfoMap);
        netInitializer.setRoute2PersonPathMap(personPathMap);
//        netInitializer.setPsgStationDistributionInfoMap(psgStationDistributionInfoMap);
        netInitializer.setPersonTrainMapByLine(personTrainMapByLine);
        netInitializer.setSceneCode(sceneCode);
        return netInitializer;
    }
    /**
     * @description: 线路组装
     *      * 1、生成一个名字的站点字典
     *      * 2、生成一个id的站点字典
     *      * 3、生成上下行轨道轨道
     *      * 4、生成停车场--停车场中装配了列车数据
     *      * 5、组装到线路数据中
     *      * 6、分配路径到每个站点
     *      * 7、分配轨道到车站
     *
     * @author:  renzhg
     * @date:  2024/11/16 10:12
     **/
    public void netLineInitializer(NetLineInitializer netLineInitializer){

        //给车辆段创建未分配的车辆
        netLineInitializer.createNoAssignMetroTrainMap();
        lineMap=netLineInitializer.assignLineRooterData();
        metroTrainNoAssigeMap=netLineInitializer.getMetroTrainNoAssigeMap();


    }



    /**
     * @description: 这个方法做了线路lineRooter组装
     *
     * @author:  renzhg
     * @date:  2024/10/24 13:38
     **/
    public void assemblyAction() {

        NetLineInitializer netLineInitializer = new NetLineInitializer();
        netLineInitializer.setLinesStationMap(linesStationMap);
        netLineInitializer.setStationMap(stationMap);
        netLineInitializer.setStationNameMap(stationNameMap);
        netLineInitializer.setParkerMap(parkerMap);
        netLineInitializer.setTrainPlanTableMapByLine(trainPlanTableMapByLine);
        netLineInitializer.setLineRooterMap(lineRooterMap);
        netLineInitializer.setPersonPathMap(personPathMap);
        netLineInitializer(netLineInitializer);




    }

/**
 * @description:
 *初始化OD和输入参数，基于场景数据类型
 * 如果场景数据类型是全天历史数据，则分配历史OD参数。
 * @author:  renzhg
 * @date:  2024/11/16 9:40
 **/
    public void queryODData2Line() {
        // 从场景代码中获取场景数据类型
        SceneDataType sceneDataType = UnitCache.sceneParamMap.get(sceneCode).getSceneType();
        // 检查场景数据类型是否为全天历史数据
        if(sceneDataType.equals(SceneDataType.allDayHistoryData)){
            // 创建一个新的HistoryOdParamService实例
//            HistoryOdParamService historyOdParamService = new HistoryOdParamService();
//            // 设置历史OD参数服务的线路映射
//            historyOdParamService.setLineMap(lineMap);
//            // 设置历史OD参数服务的线路站点映射
//            historyOdParamService.setLinesStationMap(linesStationMap);
//            historyOdParamService.setLinesStationMap(linesStationMap);
//            // 设置历史OD参数服务的线路路由器映射
//            historyOdParamService.setLineRooterMap(lineRooterMap);
//            // 过滤进入站点的人员数量API信息
//            filterNumPeopEnStationApiInfo(numPeopEnStationApiInfoMap);
//            // 分配初始历史参数
//            historyOdParamService.assignInitHistoryParam(odProbabilityApiInfoMap,numPeopEnStationApiInfoMap);
        }
        else if(sceneDataType.equals(SceneDataType.timePeriodHistoryData)){
            HistoryTimePeriodOdParamService historyTimePeriodOdParamService=new HistoryTimePeriodOdParamService();
            // 设置历史OD参数服务的线路映射
            historyTimePeriodOdParamService.setLineMap(lineMap);
            // 设置历史OD参数服务的线路站点映射
            historyTimePeriodOdParamService.setLinesStationMap(linesStationMap);
            // 设置历史OD参数服务的线路路由器映射
            historyTimePeriodOdParamService.setLineRooterMap(lineRooterMap);
            // 过滤进入站点的人员数量API信息
            filterNumPeopEnStationApiInfo(numPeopEnStationApiInfoMap);
            // 分配初始历史参数
            historyTimePeriodOdParamService.assignInitHistoryParam(odProbabilityApiInfoMap,numPeopEnStationApiInfoMap);
        }


    }

    //人员分配
    public void filterNumPeopEnStationApiInfo(Map<String, Map<String, NumPeopEnStationApiInfo>> numPeopEnStationApiInfoMap) {
        numPeopEnStationApiInfoMap.forEach((k, v) -> {
            Map<String, NumPeopEnStationApiInfo> numPeopEnStationApiInfoMap2 = new HashMap<>();
            v.forEach((k1, v1) -> {
                if (stationMap.containsKey(k1)) {
                    numPeopEnStationApiInfoMap2.put(k1, v1);
                }
            });
            v.clear();
            v.putAll(numPeopEnStationApiInfoMap2);

        });
    }


//为各个线路设置场景参数
//    public void  initSceneCode2Line(){
//        lineRooterMap.forEach((k, v) -> {
//            v.getLine().setSceneCode(sceneCode);
//        });
//
//
//    }


    public void  path2Line(){
        personPathMap.forEach((k, v) -> {
            lineRooterMap.get(v.getFirst().getLineId()).getLine().getRoute2PersonPathMap().put(k.split("_")[0], v);
        });


    }
    /**
     * @description: 通过遍历 linesStationMap 并为每条线路设置站点映射来初始化线路站点映射。
     *这涉及创建一个站点 ID 到 Station 对象的映射，并将其分配给相应的 Line 对象。
     * @author:  renzhg
     * @date:  2024/11/16 10:00
     **/
//    public void initLineStationMap() {
//        linesStationMap.forEach((k, v) -> {
//            // 从 lineAllMap 中使用键获取 Line 对象
//            Line line = lineAllMap.get(k);
//            // 初始化 LineRooter 对象// 为当前线路创建一个站点 ID 到 Station 对象的映���
//            Map<String, Station> stationLineMap = v.stream().collect(Collectors.toMap(Station::getId, station -> station));
//            // 为当前线路设置站点映射
//            line.setStationMap(stationLineMap);
//            // 分配停车场及
//        });
//
//        logger.debug("pppppp");
//    }




    public String initEveryLineFirstTrainStartTime() {
        String netStartTrainTime = "";
        lineRooterMap.forEach((k, v) -> {
            startTimeMap.put(k, v.getEarliestStartTime());
        });
        LocalTime minTime = null;
        String minTimeKey = null;
        for (Map.Entry<String, String> entry : startTimeMap.entrySet()) {
            LocalTime currentTime = LocalTime.parse(entry.getValue());
            // 第一次迭代或找到更小的时间
            if (minTimeKey==null||currentTime.isBefore(minTime)) {
                minTime = currentTime;
                minTimeKey = entry.getKey();
            }
        }
        netStartTrainTime = startTimeMap.get(minTimeKey);
        return netStartTrainTime;
    }


}
